package gov.dhs.cis.soa;

import gov.dhs.cis.soa.Constants.DataDirType;
import gov.dhs.cis.soa.Constants.EntityType;
import gov.dhs.cis.soa.data.AbstractSOAData;
import gov.dhs.cis.soa.data.Actor;
import gov.dhs.cis.soa.data.Agent;
import gov.dhs.cis.soa.data.Application;
import gov.dhs.cis.soa.data.BusinessProcess;
import gov.dhs.cis.soa.data.DataClass;
import gov.dhs.cis.soa.data.Description;
import gov.dhs.cis.soa.data.EntitiesReferences;
import gov.dhs.cis.soa.data.InfrastructureLS;
import gov.dhs.cis.soa.data.InfrastructurePS;
import gov.dhs.cis.soa.data.IntegrationComp;
import gov.dhs.cis.soa.data.IntegrationSW;
import gov.dhs.cis.soa.data.Interface;
import gov.dhs.cis.soa.data.Processes;
import gov.dhs.cis.soa.data.RelatedDataReference;
import gov.dhs.cis.soa.data.RelatedProperties;
import gov.dhs.cis.soa.data.SecurityComp;
import gov.dhs.cis.soa.data.Service;
import gov.dhs.cis.soa.data.UseCase;

import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;


public class Utils {
	private static Integer id = new Integer(10);
	static final Logger loger = Logger.getLogger(Utils.class);
	
	public static boolean isEmpty(String sData) {
		if(sData != null && sData.trim().length() > 0)
			return false;
		return true;
	}

	public static long basicHash(String string) {
		long h = 23;	//1125899906842597L; // prime
		int len = string.length();

		for (int i = 0; i < len; i++) {
			h = 31 * h + string.charAt(i);
		}
		return h;
	}
	
    public static String hash(String text) {
    	try {
    		MessageDigest md = MessageDigest.getInstance("MD5");
    		byte[] md5hash = new byte[32];
    		md.update(text.getBytes("iso-8859-1"), 0, text.length());
    		md5hash = md.digest();
        
    		byte[] data = md5hash;
	        StringBuffer buf = new StringBuffer();
	        for (int i = 0; i < data.length; i++) {
	            int halfbyte = (data[i] >>> 4) & 0x0F;
	            int two_halfs = 0;
	            do {
	                if ((0 <= halfbyte) && (halfbyte <= 9))
	                    buf.append((char) ('0' + halfbyte));
	                else
	                    buf.append((char) ('a' + (halfbyte - 10)));
	                halfbyte = data[i] & 0x0F;
	            } while(two_halfs++ < 1);
	        }
	        return buf.toString();
    	} catch (Exception e) {
    	}
    	return ""+basicHash(text);
    }    
	
	public static int convert1stchar2Int(String sData) {
		int ret = -1;
		try {
			if(!isEmpty(sData)) {
				String s = sData.substring(0, 1);
				ret = Integer.parseInt(s);
			}
		} catch (Exception e) {
			ret = -1;
		}
		return ret;
	}
	
	public static String convert2Release(String sData) {
		String ret = "-";
		if(!isEmpty(sData)) {
			ret = sData.trim().substring(0, 1);
		}
		return ret;
	}
	
	public synchronized static int getNextId() {
		synchronized (id) {
			return id++;			
		}
	}
	
	public static Description prepareDescObj(String descT, EntityType tblType) {
		if(Utils.isEmpty(descT))
			return Description.DUMMY_DESC;
		if(descT.startsWith(Constants.NL))
			descT = descT.replaceFirst("[" + Constants.NL + "]", "");
		Description d = new Description();
		d.id = Utils.getNextId();
		d.descTxt = descT;
		if(d.descTxt.length() > Constants.DESC_TEXT_SIZE)
			d.descTxt = d.descTxt.substring(0, Constants.DESC_TEXT_SIZE);
//		if(!Utils.isEmpty(tblType))
//			d.type = tblType;
//		else
//			d.type = Constants.getDescriptionType();
		return d;
	}
	
	public static Service findServiceById(int servId, List<Service>lookupList) {
		if(lookupList == null)
			return null;
		for (Service s : lookupList) {
			if (s.id == servId)
				return s;
		}
		return null;
	}

	public static IntegrationComp findIntegrationUCByName(String stereoType, String name, List<IntegrationComp> lookupList) {
		if(lookupList == null || Utils.isEmpty(name))
			return null;
		name = name.trim();
		for (IntegrationComp s : lookupList) {
			if (s.name.equalsIgnoreCase(name.trim())) {
				if(isEmpty(stereoType))
					return s;
				if(stereoType.equalsIgnoreCase(s.stereoType))
					return s;
			}
		}
		return null;
	}

	public static IntegrationComp findIntegrationUCById(int id, List<IntegrationComp> lookupList) {
		if(lookupList == null)
			return null;
		for (IntegrationComp s : lookupList) {
			if (s.id == id) {
				return s;
			}
		}
		return null;
	}

	public static IntegrationSW findIntegrationSWByName(String name, List<IntegrationSW> lookupList) {
		if(lookupList == null || Utils.isEmpty(name))
			return null;
		name = name.trim();
		for (IntegrationSW s : lookupList) {
			if (s.name.equalsIgnoreCase(name))
				return s;
		}
		return null;
	}
	
	public static IntegrationSW findIntegrationSWById(int id, List<IntegrationSW> lookupList) {
		if(lookupList == null)
			return null;
		for (IntegrationSW s : lookupList) {
			if (s.id == id)
				return s;
		}
		return null;
	}
	
	public static SecurityComp findSecurityCompByName(String name, List<SecurityComp> lookupList) {
		if(lookupList == null || Utils.isEmpty(name))
			return null;
		name = name.trim();
		for (SecurityComp s : lookupList) {
			if (s.name.equalsIgnoreCase(name))
				return s;
		}
		return null;
	}
	
	public static SecurityComp findSecurityCompById(int id, List<SecurityComp> lookupList) {
		if(lookupList == null)
			return null;
		for (SecurityComp s : lookupList) {
			if (s.id == id)
				return s;
		}
		return null;
	}

	public static InfrastructureLS findInfrastructureLSByName(String name, List<InfrastructureLS> lookupList) {
		if(lookupList == null || Utils.isEmpty(name))
			return null;
		name = name.trim();
		for (InfrastructureLS s : lookupList) {
			if (s.name.equalsIgnoreCase(name))
				return s;
		}
		//now try adding "Logical" to the logical server name and try it out..
		name += " Logical";
		for (InfrastructureLS s : lookupList) {
			if (s.name.equalsIgnoreCase(name))
				return s;
		}
		return null;
	}

	public static InfrastructureLS findInfrastructureLSById(int id, List<InfrastructureLS> lookupList) {
		if(lookupList == null)
			return null;
		for (InfrastructureLS s : lookupList) {
			if (s.id == id)
				return s;
		}
		return null;
	}

	public static InfrastructurePS findInfrastructurePSByName(String name, List<InfrastructurePS> lookupList) {
		if(lookupList == null || Utils.isEmpty(name))
			return null;
		name = name.trim();
		for (InfrastructurePS s : lookupList) {
			if (s.name.equalsIgnoreCase(name))
				return s;
		}
		return null;
	}

	public static InfrastructurePS findInfrastructurePSById(int id, List<InfrastructurePS> lookupList) {
		if(lookupList == null)
			return null;
		for (InfrastructurePS s : lookupList) {
			if (s.id == id)
				return s;
		}
		return null;
	}

	public static Application findApplicationByName(String appname, List<Application> lookupList) {
		if(lookupList == null || Utils.isEmpty(appname))
			return null;
		appname = appname.trim();
		for (Application a : lookupList) {
			if (a.name.equalsIgnoreCase(appname))
				return a;
		}
		return null;
	}

	public static Application findApplicationById(int appid, List<Application> lookupList) {
		if(lookupList == null)
			return null;
		for (Application a : lookupList) {
			if (a.id == appid)
				return a;
		}
		return null;
	}
	
	public static Service findServiceByName(String servName, List<Service> lookupList) {
		if(lookupList == null || Utils.isEmpty(servName))
			return null;
		servName = servName.trim();
		for (Service s : lookupList) {
			if (s.name.equalsIgnoreCase(servName))
				return s;
		}
		return null;
	}
	
	public static Interface findInterfaceById(int interfaceId, List<Interface> lookupList) {
		if(lookupList == null)
			return null;
		for (Interface i : lookupList) {
			if (i.id == interfaceId)
				return i;
		}
		return null;
	}
	
	public static Interface findInterfaceByName(String interfaceName, List<Interface> lookupList) {
		if(lookupList == null || isEmpty(interfaceName))
			return null;
		for (Interface i : lookupList) {
			if (i.name.equalsIgnoreCase(interfaceName))
				return i;
		}
		return null;
	}

	public static Actor findActorById(int actorId, List<Actor> lookupList) {
		if(lookupList == null)
			return null;
		for (Actor a : lookupList) {
			if (a.id == actorId)
				return a;
		}
		return null;
	}

	public static Actor findActorByName(String actorName, List<Actor> lookupList) {
		if(lookupList == null || isEmpty(actorName))
			return null;
		for (Actor a : lookupList) {
			if (a.name.equalsIgnoreCase(actorName))
				return a;
		}
		return null;
	}

	public static Processes findProcessById(int procId, List<Processes> lookupList) {
		if(lookupList == null)
			return null;
		for (Processes p : lookupList) {
			if (p.id == procId)
				return p;
		}
		return null;
	}
	
	public static Processes findProcessByName(String procName, List<Processes> lookupList) {
		if(lookupList == null || isEmpty(procName))
			return null;
		for (Processes p : lookupList) {
			if (p.name.equalsIgnoreCase(procName))
				return p;
		}
		return null;
	}

	public static UseCase findUseCaseByNumber(String usecase, List<UseCase> lookupList) {
		if(lookupList == null || isEmpty(usecase))
			return null;
		for (UseCase u : lookupList) {
			if (u.unumber.equalsIgnoreCase(usecase))
				return u;
		}
		return null;
	}

	public static UseCase findUseCaseById(int uID, List<UseCase> lookupList) {
		if(lookupList == null)
			return null;
		for (UseCase u : lookupList) {
			if (uID == u.id)
				return u;
		}
		return null;
	}

	public static DataClass findDataByName(String dataitem, List<DataClass> lookupList) {
		if(lookupList == null || isEmpty(dataitem))
			return null;
		for (DataClass d : lookupList) {
			if (d.cname.equalsIgnoreCase(dataitem))
				return d;
		}
		return null;
	}

	public static DataClass findDataByName(String stereoType, String dataitem, List<DataClass> lookupList) {
		if(lookupList == null || isEmpty(dataitem))
			return null;
		for (DataClass d : lookupList) {
			if (d.cname.equalsIgnoreCase(dataitem)) {
				if(isEmpty(stereoType))
					return d;
				if(stereoType.equalsIgnoreCase(d.stereoType))
					return d;
			}
		}
		return null;
	}
	
	public static Agent findAgentByName(String stereoType, String name, List<Agent> lookupList) {
		if(lookupList == null || isEmpty(name))
			return null;
		for (Agent a : lookupList) {
			if (a.name.equalsIgnoreCase(name.trim())) {
				if(isEmpty(stereoType))
					return a;
				if(stereoType.equalsIgnoreCase(a.stereoType))
					return a;
			}
		}
		return null;
	}

	public static Agent findAgentById(int id, List<Agent> lookupList) {
		if(lookupList == null)
			return null;
		for (Agent a : lookupList) {
			if (a.id == id) {
				return a;
			}
		}
		return null;
	}

	public static List<RelatedProperties> findAllProps(List<RelatedProperties> lookupList, EntityType refType, int refId) {
		List<RelatedProperties> retList = new ArrayList<RelatedProperties>();
		if(lookupList == null)
			return retList;
		for (RelatedProperties r : lookupList) {
			if(r.refEntityId == refId && r.refEntityType.equalsIgnoreCase(refType.toString()))
				retList.add(r);
		}
		return retList;
	}

	public static List<EntitiesReferences> findEntitiesReferences(List<EntitiesReferences> lookupList, EntitiesReferences entRef) {
		List<EntitiesReferences> retList = new ArrayList<EntitiesReferences>();
		if(lookupList == null || entRef == null)
			return retList;
		for (EntitiesReferences r : lookupList) {
			if(r.equals(entRef))
				retList.add(r);
		}
		return retList;
	}

	public static List<EntitiesReferences> findEntitiesReferencesForSourceType(List<EntitiesReferences> lookupList, int entId, EntityType entType) {
		List<EntitiesReferences> retList = new ArrayList<EntitiesReferences>();
		if(lookupList == null)
			return retList;
		for (EntitiesReferences r : lookupList) {
			if(entId == r.entityid && entType.toString().equalsIgnoreCase(r.entitytype))
				retList.add(r);
		}
		return retList;
	}

	public static List<EntitiesReferences> findEntitiesReferencesForSourceTypeHashID(List<EntitiesReferences> lookupList, String hashId, EntityType entType) {
		List<EntitiesReferences> retList = new ArrayList<EntitiesReferences>();
		if(lookupList == null)
			return retList;
		for (EntitiesReferences r : lookupList) {
			if(hashId.equalsIgnoreCase(r.srcEntityHashableId) && entType.toString().equalsIgnoreCase(r.entitytype))
				retList.add(r);
		}
		return retList;
	}

	public static List<EntitiesReferences> findEntitiesReferencesForRefTypeHashID(List<EntitiesReferences> lookupList, String hashId, EntityType entType) {
		List<EntitiesReferences> retList = new ArrayList<EntitiesReferences>();
		if(lookupList == null)
			return retList;
		for (EntitiesReferences r : lookupList) {
			if(hashId.equalsIgnoreCase(r.refEntityHashableId) && entType.toString().equalsIgnoreCase(r.reftype))
				retList.add(r);
		}
		return retList;
	}

	public static List<EntitiesReferences> findEntitiesReferencesByHashID(List<EntitiesReferences> lookupList, String srcHashId, String refHashId) {
		List<EntitiesReferences> retList = new ArrayList<EntitiesReferences>();
		if(lookupList == null)
			return retList;
		for (EntitiesReferences r : lookupList) {
			if(srcHashId.equalsIgnoreCase(r.srcEntityHashableId) && refHashId.equalsIgnoreCase(r.refEntityHashableId))
				retList.add(r);
		}
		return retList;
	}

	public static List<EntitiesReferences> findEntitiesReferencesForRefType(List<EntitiesReferences> lookupList, int entId, EntityType reftype, String refQualifier) {
		List<EntitiesReferences> retList = new ArrayList<EntitiesReferences>();
		if(lookupList == null)
			return retList;
		String locQualVar = Utils.isEmpty(refQualifier) ? null : refQualifier.trim();
		for (EntitiesReferences r : lookupList) {
			if(locQualVar != null && !locQualVar.equalsIgnoreCase(r.refQualifier))
				continue;
			if(entId == r.entityid && reftype.toString().equalsIgnoreCase(r.reftype))
				retList.add(r);
		}
		return retList;
	}

	public static List<RelatedDataReference> findRelatedDataEntities(List<RelatedDataReference> lookupList, RelatedDataReference dataEnt) {
		List<RelatedDataReference> retList = new ArrayList<RelatedDataReference>();
		if(lookupList == null || dataEnt == null)
			return retList;
		for (RelatedDataReference r : lookupList) {
			if(r.equals(dataEnt))
				retList.add(r);
		}
		return retList;
	}
/*
	public static List<RelatedProcEntities> findAllRelatedProcEntities(List<RelatedProcEntities> lookupList, int procid) {
		List<RelatedProcEntities> retList = new ArrayList<RelatedProcEntities>();
		if(lookupList == null)
			return retList;
		for (RelatedProcEntities r : lookupList) {
			if(r.procid == procid)
				retList.add(r);
		}
		return retList;
	}
*/
	public static List<RelatedDataReference> findAllRelatedDataEntities(List<RelatedDataReference> lookupList, EntityType refEntType, int refEntId) {
		List<RelatedDataReference> retList = new ArrayList<RelatedDataReference>();
		if(lookupList == null)
			return retList;
		String conRefEntParam = refEntType.toString();
		for (RelatedDataReference r : lookupList) {
			if(r.refid == refEntId && conRefEntParam.equalsIgnoreCase(r.reftype))
				retList.add(r);
		}
		return retList;
	}
	
	public static List<RelatedDataReference> createNewRefDataClasses(SOAData soaData, String dataStr, DataDirType dirType, AbstractSOAData refEntity) {
		List<RelatedDataReference> retList = null;
		
		if(!Utils.isEmpty(dataStr)) {
			retList = new ArrayList<RelatedDataReference>();
			String[] dStrList = dataStr.split("\\,");
			for(String dItem : dStrList) {
				dItem = dItem.trim();
				DataClass foundDataO = Utils.findDataByName(dItem, soaData.dataList);
				if(foundDataO == null)
					loger.error(dItem + " - DataClass not found in the list, used by - [" + refEntity.getUMLType() + " - " + refEntity.getHashableId() + "], data direction is : " + dirType);
				else {
					RelatedDataReference refItem = RelatedDataReference.getNewDataReference(foundDataO, refEntity, dirType);
					retList.add(refItem);
				}
			}
		}
		return retList;
	}

	public static BusinessProcess findBusinessProcessByName(String name, List<BusinessProcess> lookupList) {
		if(lookupList == null || isEmpty(name))
			return null;
		String compStr = null;
		for (BusinessProcess bp : lookupList) {
			compStr = bp.serialNum + " " + bp.name;
			if (compStr.equalsIgnoreCase(name.trim())) {
				return bp;
			}
		}
		return null;
	}

	public static AbstractSOAData findReferedEntityObj(SOAData soaData, EntityType findingType, int refId) {
		AbstractSOAData retObj = null;
		if(findingType == EntityType.SECCP)
			retObj = findSecurityCompById(refId, soaData.secCompList);
		else if(findingType == EntityType.INTSW)
			retObj = findIntegrationSWById(refId, soaData.intSWList);
		else if(findingType == EntityType.INTUC)
			retObj = findIntegrationUCById(refId, soaData.intCompList);
		else if(findingType == EntityType.INFPS)
			retObj = findInfrastructurePSById(refId, soaData.infPSList);
		else if(findingType == EntityType.INFLS)
			retObj = findInfrastructureLSById(refId, soaData.infLSList);
		else if(findingType == EntityType.ACTR)
			retObj = findActorById(refId, soaData.actorList);
		else if(findingType == EntityType.USEC)
			retObj = findUseCaseById(refId, soaData.useCaseList);
		else if(findingType == EntityType.SERV)
			retObj = findServiceById(refId, soaData.servList);
		else if(findingType == EntityType.PROC)
			retObj = findProcessById(refId, soaData.procList);
		else if(findingType == EntityType.INTR)
			retObj = findInterfaceById(refId, soaData.intList);
		else if(findingType == EntityType.AGNT)
			retObj = findAgentById(refId, soaData.agentList);
		else if(findingType == EntityType.APPL)
			retObj = findApplicationById(refId, soaData.appList);
		if(retObj == null)
			loger.error("Failed to locate requested Entity Object for : " + refId + " of Type : " + findingType);
		return retObj;
	}
}
